/* Programa: Jogo da Velha
    Autor: Guilherme Henrique Nunes (RA 117108)
    Turma MC102
    Versão : a
    Concluída em: 23/05/2011
    Breve Descrição:
        Jogo da velha com IA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_acodec.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_color.h>
#include <allegro5/allegro_primitives.h>

const int TELA_LARGURA = 600;
const int TELA_ALTURA = 600;
const int PECAS = 4;
const int PECA_LARGURA = 158;
const int PECA_ALTURA  = 160;


typedef struct
{
    ALLEGRO_BITMAP *up, *down;
    ALLEGRO_SAMPLE_INSTANCE *som;
    int x, y, peca;
} Celula;

typedef struct
{
    Celula cel;
    struct No *proximo;
} No;


void freeLista(No **raiz)
{
    No *aux;

    while(*raiz != NULL)
    {
        aux = (*raiz)->proximo;
        free(*raiz);
        *raiz = aux;
    }
}

No * criaLista(No * raiz)
{     /*Função do tipo apontador para lista, i.e., o tipo de função tem de ser igual ao tipo que retorna*/
    No * novo,*aux;

    novo = (No *) malloc( sizeof( No ));   /*Aloca memória do tamanho de uma célula*/

    if(novo == NULL) exit(0);    /*Se não alocar memória significa que não há memoria disponível, logo deve sair*/

    aux = raiz;                /*Corrige os apontadores de forma a retornar um apontador para a célula vazia*/
    aux->proximo = novo;
    novo->proximo = NULL;         /*Como esta deve ser a primeira função a ser executada, esta célula vazia aponta para NULL*/

    return (aux);
}

void inserirNoFim(struct No **raiz, Celula cel){
    No *novo;
    novo = (No *) malloc(sizeof(No));
    if(novo == NULL) exit(0);
    novo->cel = cel;
    novo->proximo = NULL;

    if(*raiz == NULL)
    {      // Se for o primeiro nó
        *raiz = novo;
    }
    else
    {
        No *aux;
        aux = *raiz;
        while(aux->proximo != NULL)
        {
            aux = aux->proximo;
        }
        aux->proximo = novo;
    }

}

Celula celNaPosicao(No **raiz, int pos)
{
    No *aux;
    int qual = 0;

    aux = *raiz;
    while(qual <= pos)
    {
        aux = aux->proximo;
        qual++;
    }

    return aux->cel;

}


int iniciaPecas(Celula vet[PECAS])
{
    ALLEGRO_BITMAP *red_up, *red_down, *green_up, *green_down, *yellow_up, *yellow_down, *blue_up, *blue_down;
    ALLEGRO_SAMPLE_INSTANCE *A, *B, *C, *D;

    red_up          = al_load_bitmap("red_up.bmp");
    red_down        = al_load_bitmap("red_down.bmp");
    green_up        = al_load_bitmap("green_up.bmp");
    green_down      = al_load_bitmap("green_down.bmp");
    yellow_up       = al_load_bitmap("yellow_up.bmp");
    yellow_down     = al_load_bitmap("yellow_down.bmp");
    blue_up         = al_load_bitmap("blue_up.bmp");
    blue_down       = al_load_bitmap("blue_down.bmp");


    if (!red_up || !red_down || !green_up || !green_down || !yellow_up || !yellow_down || !blue_up || !blue_down)
    {
        fprintf(stderr, "Falha ao carregar peças !\n");
        return -1;
    }

    A = al_create_sample_instance(al_load_sample("saxMi2.wav"));
    if (A)
    {
        al_set_sample_instance_playmode(A, ALLEGRO_PLAYMODE_ONCE);
        al_attach_sample_instance_to_mixer(A, al_get_default_mixer());
        al_set_sample_instance_gain(A, 1.0);
    }
    else fprintf(stderr, "Falha ao carregar som!\n");

    B = al_create_sample_instance(al_load_sample("saxSol2.wav"));
    if (B)
    {
        al_set_sample_instance_playmode(B, ALLEGRO_PLAYMODE_ONCE);
        al_attach_sample_instance_to_mixer(B, al_get_default_mixer());
        al_set_sample_instance_gain(B, 1.0);
    }
    else fprintf(stderr, "Falha ao carregar som!\n");

    C = al_create_sample_instance(al_load_sample("saxDo3.wav"));
    if (C)
    {
        al_set_sample_instance_playmode(C, ALLEGRO_PLAYMODE_ONCE);
        al_attach_sample_instance_to_mixer(C, al_get_default_mixer());
        al_set_sample_instance_gain(C, 1.0);
    }
    else fprintf(stderr, "Falha ao carregar som!\n");

    D = al_create_sample_instance(al_load_sample("saxMi3.wav"));
    if (D)
    {
        al_set_sample_instance_playmode(D, ALLEGRO_PLAYMODE_ONCE);
        al_attach_sample_instance_to_mixer(D, al_get_default_mixer());
        al_set_sample_instance_gain(D, 1.0);
    }
    else fprintf(stderr, "Falha ao carregar som!\n");

    vet[0].up   = red_up;
    vet[0].down = red_down;
    vet[0].som  = A;
    vet[0].x    = 221;
    vet[0].y    = 50;
    vet[0].peca = 0;

    vet[1].up   = green_up;
    vet[1].down = green_down;
    vet[1].som  = B;
    vet[1].x    = 40;
    vet[1].y    = 221;
    vet[1].peca = 1;

    vet[2].up   = yellow_up;
    vet[2].down = yellow_down;
    vet[2].som  = C;
    vet[2].x    = 221;
    vet[2].y    = 390;
    vet[2].peca = 2;

    vet[3].up   = blue_up;
    vet[3].down = blue_down;
    vet[3].som  = D;
    vet[3].x    = 400;
    vet[3].y    = 221;
    vet[3].peca = 3;

}

void desenhaPecas(Celula vet[PECAS])
{
    int i;

    for(i = 0; i < PECAS; i++)
    {
        al_draw_bitmap(vet[i].up, vet[i].x, vet[i].y, 0);
    }
}

int clicouCelula(Celula *cel, Celula vet[PECAS], int x, int y)
{
    int i = 0;

    for (i = 0; i < PECAS; i++)
    {
        if((x >= vet[i].x) && (x <= vet[i].x + PECA_LARGURA) && (y >= vet[i].y) && (y <= vet[i].y + PECA_ALTURA))
        {
            *cel = vet[i];
            return 1;
        }
    }
    return 0;
}

void clique(Celula celAtual)
{
    al_draw_bitmap(celAtual.down,celAtual.x,celAtual.y,0);
    al_flip_display();
    al_play_sample_instance(celAtual.som);
    al_rest(0.5);
    al_draw_bitmap(celAtual.up,celAtual.x,celAtual.y,0);
    al_flip_display();
    al_rest(0.5);
}


int main(void)
{
    ALLEGRO_DISPLAY *display;
    ALLEGRO_EVENT_QUEUE *filaEventos;
    ALLEGRO_EVENT evento;
    ALLEGRO_BITMAP *fundo;
    int x0, y0, vezComputador = 1, jogadasComp = 0, jogadasPlayer = 0, acabou = 0, aux;
    No *raiz = (No *)malloc(sizeof(No));
    Celula celAtual, vet[PECAS];

    if (!al_init())
    {
        fprintf(stderr, "Falha ao inicializar allegro!\n");
        return -1;
    }

    if (!al_init_image_addon())
    {
        fprintf(stderr, "Falha ao inicializar o complemento image!\n");
        return -1;
    }

    display = al_create_display(TELA_LARGURA, TELA_ALTURA);
    if (!display)
    {
        fprintf(stderr, "Falha ao criar display!\n");
        return -1;
    }

    // inicialização do complemento "primitives"
    if (!al_init_primitives_addon())
    {
        fprintf(stderr, "Falha ao inicializar complemento primitives!\n");
        return -1;
    }
    al_set_window_title(display, "Jogo da Velha");
    al_set_target_bitmap(al_get_backbuffer(display));

    filaEventos = al_create_event_queue();
    if (!filaEventos)
    {
        fprintf(stderr, "Falha ao criar fila de eventos!\n");
        return -1;
    }

    if (!al_init_acodec_addon())
    {
        fprintf(stderr, "Falha ao inicializar complemento acodec!\n");
        return -1;
    }

    if (!al_install_audio())
       {
           fprintf(stderr, "Falha ao instalar audio!\n");
           return -1;
       }
       else
           if (!al_reserve_samples(4))
           {
               fprintf(stderr, "Falha ao reservar samples!\n");
               return -1;
           }

    fundo = al_load_bitmap("fundo.gif");
    if (!fundo)
    {
        fprintf(stderr, "Falha ao carregar o fundo.gif\n");
        return -1;
    }

    if (!al_install_mouse())
    {
        fprintf(stderr, "Falha ao inicializar mouse!\n");
        return -1;
    }

    al_register_event_source(filaEventos, al_get_display_event_source(display));
    al_register_event_source(filaEventos, al_get_mouse_event_source());

    srand(time(NULL));

    al_draw_bitmap(fundo, 0, 0, 0);

    raiz = criaLista(raiz);
    iniciaPecas(vet);
    desenhaPecas(vet);


    while (!acabou)
    {

        al_wait_for_event(filaEventos, &evento);
        if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
        {
            break;
        }

    if(vezComputador)
    {
        inserirNoFim(&raiz,vet[rand()%4]);
        jogadasComp++;
        for(aux = 1; aux <= jogadasComp; aux++)
        clique(celNaPosicao(&raiz,aux));
        al_rest(1.0);
        vezComputador = 0;
    }
    else
        if (evento.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)
        {
                x0 = evento.mouse.x;
                y0 = evento.mouse.y;

                if(clicouCelula(&celAtual, vet, x0, y0))
                {
                   if (jogadasPlayer < jogadasComp)
                    {
                        jogadasPlayer++;
                        inserirNoFim(&raiz,celAtual);
                        clique(celAtual);
                    }

                    if(celAtual.peca != celNaPosicao(&raiz,jogadasPlayer).peca)
                    {
                        al_show_native_message_box(display,"Acabou !!", "","Voce Perdeu !!",0, 1);
                        acabou = 1;
                    }

                    if(jogadasPlayer == jogadasComp)
                    {
                        vezComputador = 1;
                        jogadasPlayer = 0;
                        al_rest(1.0);
                    }
                }
        }



        al_flip_display();

    }


    return 0;
}

